package com.kcht.itsed.mws.alespecadapter.biz;

import com.kcht.itsed.mws.alespecadapter.exceptions.NoPluginException;
import com.kcht.itsed.mws.alespecadapter.facade.*;
import com.kcht.itsed.mws.alespecadapter.model.PluginContainerModel;
import com.kcht.itsed.mws.commmodel.PhysicalReaderTemplate;
import com.kcht.itsed.mws.commmodel.TMDatatypeFormatTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 规则插件管理器
 * 是插件注册、获取接口的实现，通过接口引用
 * 
 * @author 张文硕
 *
 */
@Component
@SuppressWarnings({"unchecked","rawtypes"})
@Slf4j
public class AleSpecPluginManager implements IMwsPluginRegister,IMwsPluginNameLoader,IMwsPluginLoader{
	
	private Map<String,PluginContainerModel<Object,PhysicalReaderTemplate>> deviceClassContainer = new HashMap<>();
	private Map<String,PluginContainerModel<? extends ITagDataDecoder,TMDatatypeFormatTemplate>> tagDecoderContainer = new HashMap<>();
	private Map<String,PluginContainerModel<Object,Object>> readerMapperContainer = new HashMap<>();

	@Override
	public void  registerDeviceClass(String deviceClassName,String description,PhysicalReaderTemplate physicalReaderTemplate) {
		deviceClassContainer.put(deviceClassName, new PluginContainerModel(deviceClassName,description,physicalReaderTemplate));
	}

	
	@Override
	public void registerTagDecoder(String decoderName, String description,
			Class<? extends ITagDataDecoder> tagDecoderCls,
			TMDatatypeFormatTemplate tmDatatypeFormatTemplate) {
		tagDecoderContainer.put(decoderName, new PluginContainerModel(decoderName,description,tmDatatypeFormatTemplate,tagDecoderCls));
		
	}

	@Override
	public TMDatatypeFormatTemplate loadTagDataTemplate(String name)
			throws NoPluginException {
		if(!tagDecoderContainer.containsKey(name))throw new NoPluginException();
		return tagDecoderContainer.get(name).getTemplateObj();
	}
	
	@Override
	public void registerReaderMapper(String mapperName, String description,
			Class<? extends IReaderMapping> readerMapper) {
		readerMapperContainer.put(mapperName, new PluginContainerModel(mapperName,description,readerMapper));
	}

	
	private <V,T> List<String[]> getNameDescs(Map<String,PluginContainerModel<V,T>> pcmm){
		return pcmm.values().stream().map(d->new String[]{d.getPluginName(),d.getDescription()}).collect(Collectors.toList());
	}
	
	@Override
	public List<String[]> getDeviceClassNames() {
		return getNameDescs(deviceClassContainer);
	}
	
	
	@Override
	public Map<String, PhysicalReaderTemplate> getDeviceClassTemplates() {
		return new HashMap<String, PhysicalReaderTemplate>(){{
			for(String readerType : deviceClassContainer.keySet()){
				put(readerType, deviceClassContainer.get(readerType).getTemplateObj());
			}
		}};
	}
	
	@Override
	public Map<String, TMDatatypeFormatTemplate> getTagDataFormatTemplates() {
		return new HashMap<String, TMDatatypeFormatTemplate>(){{
			for(String t : tagDecoderContainer.keySet()){
				put(t, tagDecoderContainer.get(t).getTemplateObj());
			}
		}};
	}

	@Override
	public List<String[]> getTagDataFormatNames() {
		return tagDecoderContainer.values().stream().map(d->new String[]{d.getPluginName(),d.getDescription()}).collect(Collectors.toList());
	}

	@Override
	public List<String[]> getReaderMappingNames() {
		return getNameDescs(readerMapperContainer);
	}

	@Override
	public IReaderMapping loadReaderMapper(String name)
			throws NoPluginException {
		if(readerMapperContainer.containsKey(name))
			try {
				return (IReaderMapping) readerMapperContainer.get(name).getPluginClass().newInstance();
			} catch (InstantiationException | IllegalAccessException e) {
				log.error("",e);
				throw new NoPluginException();
			}
		throw new NoPluginException();
	}
	
	@Override
	public ITagDataDecoder loadTagDataDecoder(String name)
			throws NoPluginException {
		if(readerMapperContainer.containsKey(name))
			try {
				return (ITagDataDecoder) tagDecoderContainer.get(name).getPluginClass().newInstance();
			} catch (InstantiationException | IllegalAccessException e) {
				log.error("",e);
				throw new NoPluginException();
			}
		throw new NoPluginException();
	}
	
}
